package com.boge.socket;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.session.IoSessionConfig;
import org.apache.mina.filter.FilterEvent;
import org.slf4j.LoggerFactory;

/**
 * 事件分配器
 * @author boge
 */
public class ActionDispatcher implements IoHandler {

    private Map<Integer, ActionHandler<?>> actionMapping = new ConcurrentHashMap<Integer, ActionHandler<?>>();

    private Set<SessionListener> listeners = new CopyOnWriteArraySet<SessionListener>();

    public Map<Long, Long> sessionVerify = new HashMap<Long, Long>();
    /**
     * 已经被出现闲置状态的isSession
     */
    private Map<Long, Integer> iosIdle = new HashMap<Long, Integer>();

    public void addSessionListener(SessionListener sessionListener) {
        listeners.add(sessionListener);
    }

    /**
     * 注册动作
     *
     * @param action  动作
     * @param handler 处理器
     */
    public void registerAction(int action, ActionHandler<?> handler) {
        if (actionMapping.containsKey(action)) {
            throw new RuntimeException("动作处理器[" + action + "]已经注册");
        }
        actionMapping.put(action, handler);
        if (handler instanceof SessionListener) {
            listeners.add((SessionListener) handler);
        }

    }

    /**
     * 删除动作
     *
     * @param action 动作
     */
    public void removeAction(int action) {
        ActionHandler<?> handler = actionMapping.remove(action);
        if (handler instanceof SessionListener) {
            listeners.remove(handler);
        }
    }

    /**
     * 获取动作
     *
     * @param action 动作
     * @return
     */
    public ActionHandler<?> getAction(int action) {
        return actionMapping.get(action);
    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {
        IoSessionConfig config = session.getConfig();
        config.setReadBufferSize(2048);
        config.setIdleTime(IdleStatus.BOTH_IDLE, 10);
        sessionVerify.put(session.getId(), (long) 0);
        for (SessionListener listener : listeners) {
            listener.sessionCreated(session);
        }
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        for (SessionListener listener : listeners) {
            listener.sessionOpened(session);
        }
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        iosIdle.remove(session.getId());
        sessionVerify.remove(session.getId());
        for (SessionListener listener : listeners) {
            listener.sessionClosed(session);
        }
    }

    @Override
    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
        if (iosIdle.containsKey(session.getId())) {
            Integer count = iosIdle.get(session.getId());
            if (count < 2) {
                count++;
                session.write(new ActionData<>(1));
                iosIdle.put(session.getId(), count);
            } else {
                iosIdle.remove(session.getId());
                session.closeNow();
                LoggerFactory.getLogger(getClass()).info("有用户空闲被关闭=[" + session.getId() + " , 用户数据=" + session + "]");
            }
        } else {
            iosIdle.put(session.getId(), 1);
        }
        for (SessionListener listener : listeners) {
            listener.sessionIdle(session, status);
        }
    }

    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        if (cause instanceof IOException) {
            iosIdle.remove(session.getId());
            sessionVerify.remove(session.getId());
        }
        for (SessionListener listener : listeners) {
            listener.exceptionCaught(session, cause);
        }
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {
        for (SessionListener listener : listeners) {
            listener.messageReceived(session, message);
        }
        iosIdle.remove(session.getId());
        ActionData data = (ActionData<Object>) message;
        if (sessionVerify.containsKey(session.getId()) && data.getVerify() > sessionVerify.get(session.getId())) {
            sessionVerify.put(session.getId(), data.getVerify());
            executeActionMapping(data, session, message);
        }
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        for (SessionListener listener : listeners) {
            listener.messageSent(session, message);
        }
    }

    @Override
    public void inputClosed(IoSession session) throws Exception {
        session.closeNow();
        for (SessionListener listener : listeners) {
            listener.inputClosed(session);
        }
    }

    @Override
    public void event(IoSession session, FilterEvent filterEvent) throws Exception {
        for (SessionListener listener : listeners) {
            listener.event(session, filterEvent);
        }
    }

    /**
     * 未能发送的数据
     *
     * @param object
     */
    public void notSendData(Object object) {
        for (SessionListener listener : listeners) {
            listener.notSendData(object);
        }
    }

    public void handshakeSuccess(IoSession session) {
        for (SessionListener listener : listeners) {
            if (listener instanceof WebSessionListener) {
                ((WebSessionListener) listener).handshakeSuccess(session);
            }
        }
    }

    public void handshakeFail(IoSession session) {
        for (SessionListener listener : listeners) {
            if (listener instanceof WebSessionListener) {
                ((WebSessionListener) listener).handshakeFail(session);
            }
        }
    }

    /**
     * 执行一个  监听器
     *
     * @param data    数据
     * @param session 通信ioSession
     * @param message 未被解析的数据
     * @throws Exception
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public void executeActionMapping(ActionData data, IoSession session, Object message) throws Exception {
        int action = data.getAction();
//		log.info("检测处理器["+action+"]");
        if (!actionMapping.containsKey(action)) {
//			throw new RuntimeException("动作处理器["+action+"]未注册");
            for (SessionListener listener : listeners) {
                listener.notRegAction(session, message);
            }
            return;
        }
        actionMapping.get(action).execute(data, session);
    }

    /**
     * 注册事件
     *
     * @param handler 处理函数
     * @param actions 注册的事件
     */
    public void registerAction(ActionHandler<?> handler, int... actions) {
        for (int action : actions) {
            registerAction(action, handler);
        }
    }

}
